package com.hdax.dm.item.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdax.dm.entity.base.Area;
import com.hdax.dm.entity.base.Image;
import com.hdax.dm.entity.item.Cinema;
import com.hdax.dm.entity.item.Item;
import com.hdax.dm.entity.item.ItemType;
import com.hdax.dm.item.dto.*;
import com.hdax.dm.item.feign.BaseFeign;
import com.hdax.dm.item.feign.ImageFeign;
import com.hdax.dm.item.mappers.CinemaMapper;
import com.hdax.dm.item.mappers.ItemTypeMapper;
import com.hdax.dm.item.service.CinemaService;
import com.hdax.dm.item.service.ItemSearchService;
import com.hdax.dm.item.service.ItemService;
import com.hdax.dm.item.vo.ItemSearchVo;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class ItemSearchServiceImpl extends ServiceImpl<ItemTypeMapper, ItemType> implements ItemSearchService {

    @Autowired
    private BaseFeign baseFeign;
    @Autowired
    private RestHighLevelClient client;
    @Autowired
    private ImageFeign imageFeign;
    @Autowired
    private ItemService itemService;
    @Autowired
    private CinemaService cinemaService;
    @Autowired
    private CinemaMapper cinemaMapper;

    @Override
    public List<ItemType> itemTypes(Long parent) {
        QueryWrapper<ItemType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent",parent);
        return list(queryWrapper);
    }

    @Override
    public List<AreaDto> queryCities() {
        List<Area> areas = baseFeign.areas();
        List<AreaDto> areaDtos = new ArrayList<>();
        areas.forEach(a->{
            AreaDto dto = AreaDto.builder()
                    .id(a.getId())
                    .name(a.getName())
                    .build();
            areaDtos.add(dto);
        });
        return areaDtos;
    }

    /**
     * 通过调用ElasticSearch快速检索数据
     * @param vo
     * @return
     */
    @Override
    public ItemSearchResultDto querygoodsinfos(ItemSearchVo vo) throws Exception{
        //填入需要索引的id
        SearchRequest request = new SearchRequest("item");

        //构建搜索条件的过程
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //高亮语法编辑器
        HighlightBuilder highlightBuilder = new HighlightBuilder();

        //Elasticsearch多条件搜索 使用BoolQueryBuilder
        //我们在调用的时候,不是通过new操作来实现的,而是通过QueryBuilders的静态方法来进行对象创建的
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //动态条件封装
        //由于页面的条件是不确定个数的，所以通过判断
        if(vo.getKeyword()!=null && !vo.getKeyword().trim().equals("")){
            //设置语法的高亮
            //                                                                   要给哪个属性增加高亮
            HighlightBuilder.Field highlightFiled =new HighlightBuilder.Field("itemname");
            // 内置高亮语法
            highlightFiled.highlighterType("unified");
            //设置语法高亮对象
            highlightBuilder.field(highlightFiled);

            //拼接itemname的匹配度查询
            //                                                    字段名称     字段所对应的关键词
            boolQueryBuilder.must(QueryBuilders.matchQuery("itemname",vo.getKeyword()));

            //should:不影响查询结果条数，但是影响排名评分
            boolQueryBuilder.should(QueryBuilders.matchQuery("abstractmessage",vo.getKeyword()));
        }

        //根据地区查询
        if(vo.getAreaId()!=0){
            boolQueryBuilder.must(QueryBuilders.matchQuery("areaid",vo.getAreaId()));
        }

        //多个must条件连接方式是and,条件要成立就全部成立
        //一二级分类
        if(vo.getItemTypeId1()!=0){
            boolQueryBuilder.must(QueryBuilders.termQuery("itemtype1id",vo.getItemTypeId1()));
        }
        if(vo.getItemTypeId2()!=0){
            boolQueryBuilder.must(QueryBuilders.termQuery("itemtype2id",vo.getItemTypeId2()));
        }
        //时间范围查询
        if(!vo.getStartTime().equals("") && vo.getEndTime()!=null){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("starttime");
            rangeQueryBuilder.gte(vo.getStartTime()+"T00:00:00");//大于某个时间
            rangeQueryBuilder.lte(vo.getEndTime()+"T23:59:59");//小于某个时间
            boolQueryBuilder.must(rangeQueryBuilder);
        }
        //排序
        if(vo.getSort().equals("recommend"))
            builder.sort("isrecommend", SortOrder.DESC);
        if(vo.getSort().equals("recentshow"))
            builder.sort("starttime", SortOrder.DESC);
        if(vo.getSort().equals("reccentsell"))
            builder.sort("createtime",SortOrder.DESC);

        //执行查询封装
        builder.query(boolQueryBuilder);

        //设置高亮的样式
        highlightBuilder.requireFieldMatch(true);
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        builder.highlighter(highlightBuilder);

        //分页查询
        builder.from((vo.getCurrentPage()-1)*vo.getPageSize());
        builder.size(vo.getPageSize());
        request.source(builder);
        //client是由RestHighLevelClient这个对象来的
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //搜索的数据,是个数组
        SearchHit[] searchHits = response.getHits().getHits();

        ItemSearchResultDto resultDto = new ItemSearchResultDto();
        //当前的页数
        resultDto.setCurrentPage(vo.getCurrentPage());
        //每页显示的条数
        resultDto.setPageSize(vo.getPageSize());

//        resultDto.setRows(new ArrayList<ItemRowsDto>());如果没有实例化,这个就可以接触注释了
        //总条数
        resultDto.setPageCount(response.getHits().getTotalHits().value % vo.getPageSize() == 0?
                response.getHits().getTotalHits().value / vo.getPageSize():
                response.getHits().getTotalHits().value / vo.getPageSize()+1);

        //遍历searchHits这个数组
        for (int i = 0; i < searchHits.length; i++) {
            //每一行搜索到的商品数据
            //                           这个是一个JSON数据(这个里面的属性需要与之对应)      转换成谁,对应的实体类
            ItemRowsDto rowsDto = JSON.parseObject(searchHits[i].getSourceAsString(), ItemRowsDto.class);
            //远程调用
            rowsDto.setImgUrl(imageFeign.image(rowsDto.getId(),2L,1L)==null?"":imageFeign.image(rowsDto.getId(),2L,1L).getImgUrl());
            //判断如果每页输入,不进入
            if(vo.getKeyword()!=null&&!vo.getKeyword().equals("")) {
                rowsDto.setItemName(StringUtils.arrayToDelimitedString(searchHits[i].getHighlightFields().get("itemname").getFragments(), ""));
            }
            //已经在ItemSearchResultDto中实例化,如果没有在ItemSearchResultDto中实例化,需要在上方,去setRows再去实例化(125行)哪个
            resultDto.getRows().add(rowsDto);
        }

        resultDto.setTotal(response.getHits().getTotalHits().value);
        return resultDto;

    }
    /**
     * 今日推荐
     * @return
     */
    @Override
    public List<HotItemDto> recommend() {
        //进入数据库查询
        QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("state",3).last("limit 0,5");
        List<HotItemDto> hotItemDto=new ArrayList<>();
        List<Item> itemList=itemService.list(queryWrapper);
        itemList.forEach(a->{
            HotItemDto hotItemDto1=new HotItemDto().builder()
                    .id(a.getId())
                    .itemName(a.getItemName())
                    .minPrice(a.getMinPrice())
                    .imgUrl(imageFeign.image(a.getId(),2L,1L)==null ? "" :imageFeign.image(a.getId(),2L,1L).getImgUrl())
                    .build();
            hotItemDto.add(hotItemDto1);
        });
        return hotItemDto;
    }

    /**
     * 即将开售
     * @return
     */
    @Override
    public List<HotItemDto> sell() {

        //进入数据库查询
        QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
        //放入查询条件
        queryWrapper.eq("state",2).last("limit 0,5");
        List<HotItemDto> hotItemDto=new ArrayList<>();
        List<Item> itemList=itemService.list(queryWrapper);
        //循环添加
        itemList.forEach(a->{
            HotItemDto hotItemDto1=new HotItemDto().builder()
                    .id(a.getId())
                    .itemName(a.getItemName())
                    .minPrice(a.getMinPrice())
                    .imgUrl(imageFeign.image(a.getId(),2L,1L)==null ? "" :imageFeign.image(a.getId(),2L,1L).getImgUrl())
                    .build();
            hotItemDto.add(hotItemDto1);
        });
        return hotItemDto;
    }

    /**
     * 猜你喜欢
     * @return
     */
    @Override
    public List<ItemsDto> guesslike(Long itemTypeId) {

        List<ItemsDto> items=new ArrayList<>();
        QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("itemType1Id",itemTypeId);
        /**
         * 差几条
         */
        IPage<Item> itemIPage=itemService.page(new Page<Item>(1,5),queryWrapper);
        itemIPage.getRecords().forEach(item -> {
            Cinema ciname = cinemaMapper.selectById(item.getCinemaId());
            Image image = imageFeign.image(item.getId(),2L,1L);
            items.add(
                    ItemsDto.builder()
                            .id(item.getId())
                            .itemName(item.getItemName())
                            .imgUrl(image == null || image.getImgUrl() == null ?"":image.getImgUrl())
                            .areaId(item.getCinemaId())
                            .areaName(ciname.getAreaName())
                            .address(ciname.getAddress())
                            .startDate(LocalDateTime.parse(String.valueOf(item.getStartTime())))
                            .endDate(LocalDateTime.parse(String.valueOf(item.getEndTime())))
                            .minPrice(item.getMinPrice())
                            .build()

            );
        });
        return items;
    }

    @Override
    public List<ItemsDto> guesslikes(Long itemTypeId) {
        List<ItemsDto> items=new ArrayList<>();
        QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("itemType1Id",itemTypeId);
        /**
         * 差几条
         */
        IPage<Item> itemIPage=itemService.page(new Page<Item>(1,6),queryWrapper);
        itemIPage.getRecords().forEach(item -> {
            Cinema ciname = cinemaMapper.selectById(item.getCinemaId());
            Image image = imageFeign.image(item.getId(),2L,1L);
            items.add(
                    ItemsDto.builder()
                            .id(item.getId())
                            .itemName(item.getItemName())
                            .imgUrl(image == null || image.getImgUrl() == null ?"":image.getImgUrl())
                            .areaId(item.getCinemaId())
                            .areaName(ciname.getAreaName())
                            .address(ciname.getAddress())
                            .startDate(LocalDateTime.parse(String.valueOf(item.getStartTime())))
                            .endDate(LocalDateTime.parse(String.valueOf(item.getEndTime())))
                            .minPrice(item.getMinPrice())
                            .build()

            );
        });
        return items;
    }

    @Override
    public List<HotItemDto> recommends() {
        //进入数据库查询
        QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("state",3).last("limit 0,8");
        List<HotItemDto> hotItemDto=new ArrayList<>();
        List<Item> itemList=itemService.list(queryWrapper);
        itemList.forEach(a->{
            HotItemDto hotItemDto1=new HotItemDto().builder()
                    .id(a.getId())
                    .itemName(a.getItemName())
                    .minPrice(a.getMinPrice())
                    .imgUrl(imageFeign.image(a.getId(),2L,1L)==null ? "" :imageFeign.image(a.getId(),2L,1L).getImgUrl())
                    .build();
            hotItemDto.add(hotItemDto1);
        });
        return hotItemDto;
    }
    @Override
    public List<ItemsDto> guesslikeqs(Long itemTypeId) {
        List<ItemsDto> items=new ArrayList<>();
        QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("itemType1Id",itemTypeId);
        /**
         * 差几条
         */
        IPage<Item> itemIPage=itemService.page(new Page<Item>(1,7),queryWrapper);
        itemIPage.getRecords().forEach(item -> {
            Cinema ciname = cinemaMapper.selectById(item.getCinemaId());
            Image image = imageFeign.image(item.getId(),2L,1L);
            items.add(
                    ItemsDto.builder()
                            .id(item.getId())
                            .itemName(item.getItemName())
                            .imgUrl(image == null || image.getImgUrl() == null ?"":image.getImgUrl())
                            .areaId(item.getCinemaId())
                            .areaName(ciname.getAreaName())
                            .address(ciname.getAddress())
                            .startDate(LocalDateTime.parse(String.valueOf(item.getStartTime())))
                            .endDate(LocalDateTime.parse(String.valueOf(item.getEndTime())))
                            .minPrice(item.getMinPrice())
                            .build()

            );
        });
        return items;
    }


    /**
     * 楼层
     * @return
     */
    @Override
    public List<FloorDto> floor() {
        List<FloorDto> floorDtoList= new ArrayList<>();
        //查询所有的父id
        QueryWrapper<ItemType> fuquery=new QueryWrapper();
        //查询全部楼层信息 默认查最大等级
        List<ItemType> fulou=list(fuquery.eq("parent", 0));
        //根据楼层信息查到内部信息
        fulou.forEach(itemtype->{
            List<ItemsDto> itemsDtoList = new ArrayList<ItemsDto>();
           QueryWrapper<Item> spquery=new QueryWrapper<>();
           List<Item> splist=itemService.list(spquery.eq("itemType1Id",itemtype.getId()).last("limit 0,5"));
           splist.forEach(address->{
               ItemsDto itemsDto = new ItemsDto();
               QueryWrapper<Cinema> queryWrapper1 = new QueryWrapper<Cinema>();
               queryWrapper1.eq("id",address.getCinemaId());
               //把转换后的数据放入
               BeanUtils.copyProperties(address,itemsDto);
               //城市查询
               BeanUtils.copyProperties(cinemaMapper.selectOne(queryWrapper1),itemsDto);
               itemsDto.setStartDate(address.getStartTime());
               itemsDto.setEndDate(address.getEndTime());
               //远程调用base微服务中的image表中的方法 根据商品id等条件查询商品图片
               itemsDto.setImgUrl(imageFeign.image(address.getId(),2L,1L)==null?"":imageFeign.image(address.getId(),2L,1L).getImgUrl());
               itemsDtoList.add(itemsDto);
           });
            //信息存入
            floorDtoList.add(FloorDto.builder()
                    .index(itemtype.getId())
                    .itemTypeName(itemtype.getAliasName())
                    .itemTypeId(itemtype.getId())
                    .items(itemsDtoList)
                    .build());
        });

        return floorDtoList;
    }

    /**
     * 查询不同分类排行
     * @return
     */
    @Override
    public List<ItemsDto> seniority(Map<String,String> map) {
        //根据类型编号查询
        QueryWrapper<Item> itemWrapper = new QueryWrapper<>();
        //查询推荐并限制条
        itemWrapper.eq("itemType1Id",map.get("itemTypeId"));
        itemWrapper.eq("isBanner",1);
        itemWrapper.eq("isRecommend",1);
        itemWrapper.last("limit 13");
        List<Item> items =itemService.list(itemWrapper);
        List<ItemsDto> itemsDtoList = new ArrayList<>();
        items.forEach(item->{
            ItemsDto itemsDto = new ItemsDto();
            //数据转换
            BeanUtils.copyProperties(item,itemsDto);
            itemsDtoList.add(itemsDto);
        });
        return itemsDtoList;
    }


}
